Subsystem 2a-ii: oil-rig activation detection (small/large) via CH47 + 3-state machine + #events/in-game alerts + /small //large - #14
Merged
Conversation
…angedEvent Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ive poll cadence Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Implements subsystem 2a-ii oil-rig lifecycle detection and alerting by inferring rig activation from CH47 movement near monument coordinates, then driving a 3-state in-memory rig state machine and broadcasting alerts to both Discord #events and in-game team chat. This extends the existing live-events marker poller and command surface added in 2a.
Changes:
- Add CH47→oil-rig activation detection (small/large) with adaptive marker polling and monument lookup on connect.
- Introduce an in-memory rig state machine + periodic tick to emit timed boundaries (crate lootable / respawned).
- Add rig status commands (
!small/!largeand/small//large) plus generalized in-game broadcasts for all live events.
Reviewed changes
Copilot reviewed 35 out of 35 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/RustPlusBot.Features.Events.Tests/State/RigStateStoreTests.cs | Adds unit coverage for rig state transitions and timers. |
| tests/RustPlusBot.Features.Events.Tests/Rendering/RigRenderingTests.cs | Adds tests for rig embed + in-game line rendering. |
| tests/RustPlusBot.Features.Events.Tests/Relaying/EventRelayTests.cs | Extends relay tests for in-game broadcasts and rig relaying behavior. |
| tests/RustPlusBot.Features.Events.Tests/Hosting/EventsHostedServiceTickTests.cs | Adds test for the rig-timer tick publishing boundary events. |
| tests/RustPlusBot.Features.Events.Tests/EventRegistrationTests.cs | Updates DI registration test setup for new rig/broadcast dependencies. |
| tests/RustPlusBot.Features.Connections.Tests/Fakes/FakeRustSocketSource.cs | Adds monuments support to the fake socket connection for supervisor tests. |
| tests/RustPlusBot.Features.Connections.Tests/ConnectionSupervisorTests.cs | Adds integration-style tests for CH47 entering/leaving rig radius. |
| tests/RustPlusBot.Features.Connections.Tests/ConnectionOptionsTests.cs | Verifies new ConnectionOptions defaults (poll cadence, rig windows/radius). |
| tests/RustPlusBot.Features.Commands.Tests/Handlers/RigCommandHandlersTests.cs | Adds tests for !small/!large command replies. |
| tests/RustPlusBot.Features.Commands.Tests/CommandRegistrationTests.cs | Updates command registration tests for new rig handlers and IRigState. |
| tests/RustPlusBot.Abstractions.Tests/Events/RigStateChangedEventTests.cs | Adds tests for new rig event and monument snapshot DTOs. |
| src/RustPlusBot.Host/Program.cs | Adds startup validation for new rig and fast-poll options. |
| src/RustPlusBot.Features.Events/State/RigStatus.cs | Introduces rig lifecycle status enum (Online/Active/Offline). |
| src/RustPlusBot.Features.Events/State/RigStateStore.cs | Implements the in-memory rig state machine with timer advancement. |
| src/RustPlusBot.Features.Events/State/RigState.cs | Adds a value type for point-in-time rig state reads. |
| src/RustPlusBot.Features.Events/State/IRigState.cs | Adds rig state read interface for commands and other consumers. |
| src/RustPlusBot.Features.Events/Rendering/EventLocalizationCatalog.cs | Adds localized strings for rig events and in-game “.line” variants. |
| src/RustPlusBot.Features.Events/Rendering/EventEmbedRenderer.cs | Adds rig embed + rig line rendering; adds in-game rendering for other events. |
| src/RustPlusBot.Features.Events/Relaying/EventRelay.cs | Relays events to Discord + in-game team chat; applies rig activation events to state. |
| src/RustPlusBot.Features.Events/Hosting/EventsHostedService.cs | Adds rig event consumer loop + rig tick loop; clears rig state on disconnect. |
| src/RustPlusBot.Features.Events/EventServiceCollectionExtensions.cs | Registers RigStateStore / IRigState in DI. |
| src/RustPlusBot.Features.Connections/Supervisor/ConnectionSupervisor.cs | Fetches monuments on connect, detects rig activation during marker polling, adds adaptive poll cadence. |
| src/RustPlusBot.Features.Connections/Listening/RustPlusSocketSource.cs | Implements GetMonumentsAsync via Rust+ GetMap. |
| src/RustPlusBot.Features.Connections/Listening/IRustServerConnection.cs | Extends connection contract with GetMonumentsAsync. |
| src/RustPlusBot.Features.Connections/ConnectionOptions.cs | Adds rig-related config and fast marker poll interval; updates poll default to 5s. |
| src/RustPlusBot.Features.Commands/Modules/ServerCommandModule.cs | Adds /small and /large slash commands. |
| src/RustPlusBot.Features.Commands/Localization/CommandLocalizationCatalog.cs | Adds EN/FR localized responses for rig status commands. |
| src/RustPlusBot.Features.Commands/Handlers/SmallCommandHandler.cs | Implements !small command handler. |
| src/RustPlusBot.Features.Commands/Handlers/RigReply.cs | Adds shared formatting logic for rig status replies. |
| src/RustPlusBot.Features.Commands/Handlers/LargeCommandHandler.cs | Implements !large command handler. |
| src/RustPlusBot.Features.Commands/CommandServiceCollectionExtensions.cs | Registers new rig command handlers. |
| src/RustPlusBot.Abstractions/Events/RigStateChangedEvent.cs | Adds event contract for rig lifecycle boundaries. |
| src/RustPlusBot.Abstractions/Events/RigKind.cs | Adds small/large rig enum. |
| src/RustPlusBot.Abstractions/Events/RigEventKind.cs | Adds rig boundary kind enum (Activated/Lootable/Respawned). |
| src/RustPlusBot.Abstractions/Connections/MonumentSnapshot.cs | Adds monument DTO used to locate rigs via GetMap. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+53
to
+55
| // Transfer any pre-staged monuments so they are available before the supervisor fetches them on connect. | ||
| connection.MonumentsResult = _pendingMonuments; | ||
|
|
Comment on lines
+71
to
+79
| public void Apply(RigStateChangedEvent activated) | ||
| { | ||
| ArgumentNullException.ThrowIfNull(activated); | ||
| var key = (activated.GuildId, activated.ServerId, activated.Rig); | ||
| lock (Gate) | ||
| { | ||
| _rigs[key] = new Entry(RigStatus.Active, clock.UtcNow, activated.X, activated.Y, activated.Dimensions); | ||
| } | ||
| } |
Comment on lines
+527
to
+533
| #pragma warning disable CA1031 // Broad catch: a monuments-fetch failure just disables rig detection this window. | ||
| catch (Exception ex) | ||
| #pragma warning restore CA1031 | ||
| { | ||
| LogMarkerPollFailed(logger, ex, | ||
| Guid.Empty); // reuse the marker-poll-failed log; rig detection degrades gracefully | ||
| return []; |
Comment on lines
+1
to
+4
| using Microsoft.Extensions.DependencyInjection; | ||
| using Microsoft.Extensions.Logging.Abstractions; | ||
| using Microsoft.Extensions.Options; | ||
| using NSubstitute; |
Comment on lines
+1
to
+4
| using RustPlusBot.Abstractions.Events; | ||
| using RustPlusBot.Features.Connections.Listening; | ||
| using RustPlusBot.Features.Events.Classifying; | ||
| using RustPlusBot.Features.Events.Rendering; |
- FakeRustSocketSource: reset _pendingMonuments after transfer in Create() so SetMonuments applies to the NEXT connection only (no cross-connection leak / test order-dependence). - RigStateStore.Apply: fail-fast ArgumentException when Kind != Activated (the timed kinds come from Advance, not Apply); add a Theory covering both. - ConnectionSupervisor: dedicated LogMonumentsFetchFailed message threading the real server id (was misattributed to LogMarkerPollFailed with Guid.Empty). - Remove genuinely-unused usings (NSubstitute + Connections.Listening in RigStateStoreTests; Connections.Listening in RigRenderingTests). Kept the usings Copilot flagged that are actually in use (M.E.DependencyInjection for IServiceScopeFactory in the tick test; Classifying for RustMapEvent/MapEventKind). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Owner
Author
|
Addressed the Copilot review in
Build 0/0 strict, jb-clean, full suite green (323 tests across 8 assemblies). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements small/large oil-rig activation detection — the CH47 workaround deferred out of 2a. Since the current Rust game no longer sends locked-crate map markers, rig status is inferred from CH47 (Chinook) movement: a CH47 entering an oil-rig monument's radius marks that rig as activated.
This is the second slice of subsystem 2 (live events). Builds on 2a (#13).
What it does
ConnectionSupervisor): fetches rig monuments once on connect (oilrig_1= small,large_oil_rig= large), and on each marker poll fires a rig-activation event when a CH47 enters a rig's radius (debounced once per visit). Marker poll cadence is now adaptive — 5s base, 2s while a CH47 is live (to catch the brief at-rig visit). The existing cargo/heli/chinook marker path is unchanged; the generic "Chinook spawned" event still fires alongside a rig activation.RigStateStore, in-memory, per(guild, server, rig)):Online(armed, assumed on connect) → CH47 →Active(combat phase, ~15m) →Offline(crate lootable/looted, ~15m) →Online. A 30s background tick advances the two timed boundaries.#eventsand broadcast a localized in-game team-chat line. The in-game broadcast was generalized to every live event (cargo/heli/chinook too, 1:1 with#events).!small/!largein-game commands +/small//largeslash commands report rig status + time remaining.All configurable:
RigRadius(150),RigActiveWindow/RigOfflineWindow(15m),RigTickInterval(30s),MarkerPollInterval(5s) /MarkerPollFastInterval(2s).Scope notes
Online→Offlinetransition is unobservable, so it's a best-effort timer; rig state is a best-effort inference, re-synced on the next real CH47 activation.Tests & quality
ReformatAndReorderclean; no EF model drift.🤖 Generated with Claude Code